﻿using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using Sonce.Editor.Data;

namespace Sonce.Editor.Tools
{
	public class ElementTool : IEditorTool
	{
		#region Constructors
		/// <summary>
		/// Initializes a new ElementTool instance.
		/// </summary>
		public ElementTool()
		{
		}

		/// <summary>
		/// Initializes a new ElementTool instance.
		/// </summary>
		public ElementTool(ElementTag tag)
		{
			this.Tag = tag;
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets a tag taht represents elements.
		/// </summary>
		public ElementTag Tag
		{
			get;
			set;
		}
		#endregion

		#region IEditorTool Members
		public Editor Editor
		{
			get;
			set;
		}

		public bool KeyDown(Key key)
		{
			return false;
		}

		public bool KeyUp(Key key)
		{
			return false;
		}

		public bool MouseDown(Point position)
		{
			FrameworkElement element = DrawElement(this.Editor.LayerPreview, this.Tag, position);
			LayoutManager.Transform(element, this.Editor.Angle, null, null);
			return true;
		}

		public bool MouseUp(Point position)
		{
			this.Editor.LayerPreview.Clear();
			this.Editor.SelectionManager.UnselectAll();
			FrameworkElement element = DrawElement(this.Editor.LayerWorking, this.Tag, position);
			LayoutManager.Transform(element, this.Editor.Angle, null, null);
			//FrameworkElement element = DrawResourceElement(this.Editor.LayerWorking, position, "Element", this.Xaml);
			return true;
		}

		public bool MouseMove(Point position, bool isMouseDown)
		{
			if (isMouseDown)
			{
				FrameworkElement element = DrawElement(this.Editor.LayerPreview, this.Tag, position);
				LayoutManager.Transform(element, this.Editor.Angle, null, null);
			}
			return true;
		}

		public bool MouseEnter()
		{
			return false;
		}

		public bool MouseLeave()
		{
			this.Editor.ReleaseTool();
			return true;
		}

		public bool MouseWheel(int delta)
		{
			return false;
		}
		#endregion

		#region Draw methods
		/// <summary>
		/// Draw a custom xaml element at the specified location.
		/// </summary>
		/// <param name="position">Top left corner of the element.</param>
		/// <param name="xaml">Xaml representation of the element.</param>
		/// <returns>Returns the drawn visual object for futher customization.</returns>
		public FrameworkElement DrawElement(Layer layer, ElementTag tag, Point position)
		{
			FrameworkElement visual = null;
			if (layer != null && this.Tag != null && !string.IsNullOrEmpty(this.Tag.Xaml))
			{
				object obj = XamlReader.Load(this.Tag.Xaml);
				if (obj != null && obj is FrameworkElement)
				{
					visual = obj as FrameworkElement;
					layer.Draw(visual, position);

					//Attach ElementTag only if layer is permanent (not floating)
					if (layer == this.Editor.LayerWorking) //TODO: Or it's sub layer
					{
						//Insert element into local database
						EditorDataContext db = new EditorDataContext();
						Element element = new Element();
						element.DocumentId = this.Editor.CurrentDocumentId;
						element.ElementPrototypeId = tag.GetPrototypeId();
						element.X = position.X;
						element.Y = position.Y;
						element.Angle = this.Editor.Angle;
						element.Label = tag.Label;
						element.Value = tag.Value;
						db.Elements.Add(element);

						//Insert nodes into local database
						tag.Nodes = tag.GetNodes(visual);
						foreach (var item in tag.Nodes)
						{
							Node node = new Node();
							node.DocumentId = this.Editor.CurrentDocumentId;
							//TODO: node.ElementId = element.Id;
							//TODO: node.ElementNodeIndex = i; //Which node of an element
							//node.Label = item.Label;
							node.X = item.Position.X;
							node.Y = item.Position.Y;
							db.Nodes.Add(node);
						}

						//Indicates that this is a fixed visual object (cannot be ungrouped or exploded)
						tag.Id = element.Id;
						visual.Tag = tag;
					}
				}
			}
			return visual;
		}
		#endregion

		#region Under development
		/*
        /// <summary>
        /// Draw a custom xaml element at the specified location. Element is created in resources with unique 'name'
        /// and it is reused when next element by the same 'name' is drawn.
        /// </summary>
        /// <param name="position">Top left corner of the element.</param>
        /// <param name="xaml">Xaml representation of the element.</param>
        /// <returns>Returns the drawn visual object for futher customization.</returns>
        public FrameworkElement DrawResourceElement(Point position, string name, string xaml)
        {
            //Under development
            FrameworkElement element = null;

            //Button control = new Button();

            //Style style = null;
            //if (this.Resources.Contains(name))
            //{
            //    style = (Style)this.Resources[name];
            //}
            //else if (!string.IsNullOrEmpty(xaml))
            //{
            //    // http://weblogs.asp.net/scottgu/pages/silverlight-tutorial-part-7-using-control-templates-to-customize-a-control-s-look-and-feel.aspx
            //    //ControlTemplate template = new ControlTemplate();
            //    //template.TargetType = typeof(Control);
            //    //ControlTemplate

            //    ControlTemplate template = Helper.CreateControlTemplate(xaml);
            //    //template.TargetType = typeof(Button); //Cannot be applied at the current object state

            //    style = new Style(typeof(Button));
            //    style.Setters.Add(new Setter(Button.WidthProperty, 100));
            //    style.Setters.Add(new Setter(Button.HeightProperty, 100));
            //    style.Setters.Add(new Setter(Button.TemplateProperty, template));
            //    //control.Template = template; //TODO: Remove xmlns before creating ControlTemplate
            //    //NOTE: Silverlight does not support DynamicResources, programatically attaching resources may seem like that
            //    //Google: how to put FrameworkElement in the resources

            //    this.Resources.Add(name, style);
            //}

            //if (style != null)
            //{
            //    //control.Style = style;
            //    control.Margin = new Thickness(position.X, position.Y, 0, 0);
            //    if (this.isFloating)
            //    {
            //        this.Children.Clear();
            //    }
            //    this.Children.Add(control);
            //    //OnVisualObjectDrawn(new LayerEventArgs(element, position));
            //}

            return element;
        }
        */
		#endregion
	}
}
